遍历一个字符串
在Java 8中,CharSequence接口新添加了一个方法叫做chars(),方法的签名是这个样子的:
public default IntStream chars()
default关键字修饰的接口方法是Java 8中新添加的特性,目的是向接口中添加已经实现的方法。chars()方法返回了一个IntStream类型,所以chars()实际上是为所有实现了CharSequence接口的类型(String类,StringBuffer类,StringBuilder类等)开启了通往函数式编程和Lambda表达式的大门。
既然得到了IntStream类型的实例,那么下一步就可以使用内部遍历器forEach进行遍历了:
final String str = "w00t";
str.chars().forEach(ch -> System.out.println(ch));
对于如println之类的静态方法,也可以使用方法引用来简化Lambda表达式的书写:
str.chars().forEach(System.out::println);
Java编译器会自动地将目标字符串的每一个字符作为参数传入到System.out.println方法中。然而正是因为返回的Stream是IntStream类型,所以打印出来的是一个个的数字而不是我们期待的字符。可以使用下面的类型转换来确保打印的是字符:
public class IterateString {
public static void printChar(int aChar) {
System.out.println((char)(aChar));
}
}
str.chars().forEach(IterateString::printChar);
为了解决这种常见的问题,IntStream提供了一个mapToObj方法用来执行Int类型到其它任意类型的转换,该方法的签名和其相关的函数接口IntFunction如下:
<U> Stream<U> mapToObj(IntFunction<? extends U> mapper);
@FunctionalInterface
public interface IntFunction<R> {
R apply(int value);
}
根据mapToObj的签名,整型类型到字符类型的转换和输出就可以这样实现了:
str.chars()
.mapToObj(ch -> Character.valueOf((char)ch))
.forEach(System.out::println);
因为chars()返回的是Stream类型,因此它也开启了诸多的可能性,比如使用filter方法:
str.chars()
.filter(ch -> Character.isDigit(ch))
.forEach(ch -> IterateString.printChar(ch));
// 使用方法引用
str.chars().filter(Character::isDigit).forEach(IterateString::printChar);
参数路由(Parameter Routing)
我们已经看到了方法引用的两种类型:
- 实例方法的引用
- 静态方法的引用
编译器在处理这两种引用类型时,会有一点点不同: 在处理实例方法引用诸如String::toUpperCase时,集合中的元素会被当做调用目标,如果以element表示集合中的元素的话,最终的调用是这样的:element.toUpperCase()。
在处理静态方法引用诸如Character.isDigit时,集合中的元素会被当做方法的参数传入:Character.isDigit(element)。